package org.liaohailong.lib

import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes

/**
 * Describe:
 *
 *
 * @author liaohailong
 * Time: 2021/11/16 14:48
 */
class HelloWorldClassVisitor(cw: ClassWriter) : ClassVisitor(Opcodes.ASM7, cw) {

    private lateinit var className: String

    // callback when visit class
    override fun visit(
        version: Int,
        access: Int,
        name: String,
        signature: String?,
        superName: String?,
        interfaces: Array<out String>?,
    ) {
        super.visit(version, access, name, signature, superName, interfaces)
        className = name
    }

    // callback when visit method in the class
    override fun visitMethod(
        access: Int,
        name: String?,
        descriptor: String,
        signature: String?,
        exceptions: Array<out String>?,
    ): MethodVisitor = object : MethodVisitor(
        api,
        cv.visitMethod(access, name, descriptor, signature, exceptions)
    ) {
        val monitorClassName = "org/liaohailong/transformapp/TimeMonitor"
        val key = "${className}-${name}-${descriptor}"

        // callback when method begin
        override fun visitCode() {

            if (className == monitorClassName)
                return super.visitCode()


            mv.visitLdcInsn(key)

            mv.visitMethodInsn(
                Opcodes.INVOKESTATIC,
                monitorClassName,
                "start",
                "(Ljava/lang/String;)V",
                false
            )
        }


        // callback when walking the lines
        override fun visitInsn(opcode: Int) {
            if (className == monitorClassName)
                return super.visitInsn(opcode)

            if (opcode in Opcodes.IRETURN..Opcodes.RETURN){
                mv.visitLdcInsn(key)
                mv.visitMethodInsn(
                    Opcodes.INVOKESTATIC,
                    monitorClassName,
                    "end",
                    "(Ljava/lang/String;)V",
                    false
                )
            }
            super.visitInsn(opcode)
        }
    }
}